<?php
namespace App\Utility;

use EasySwoole\RedisPool\Redis;
use EasySwoole\RedisPool\Connection;
use Swoole\Coroutine\Redis as RedisServer; // 使用原选的服务
use App\Utility\Pool\RedisPool;

/**
 * TODO 自定义REDIS操作
 *
 * @author Administrator
 */
class RedisTools
{

    const poolName = 'redis';

    public function __construct()
    {}

    public function select($db = 0)
    {
        RedisPool::invoke(function (RedisServer $redis) use ($db) {
            $redis->select($db);
        });
    }

    /**
     * String 操作数据
     * @param number $db
     * @return mixed
     */
    public function get($key, $db = 0)
    {
        return self::Pool_get($key,$db);
    }
    public function set($key, $value, $timeout, $db = 0)
    {
        return self::Pool_set($key, $value, $timeout, $db);
    }
    public function del($key, $db = 0)
    {
        return self::Pool_del($key,$db);
    }
    
    // 新加方法
    public function setRedisValue($key, $value, $timeout)
    {
        $this->set($key, $value, $timeout, 0);
    }
    

    /**
     * Hash操作数据
     * @param number $db
     * @return mixed
     */
    public function hGet($key, $mainId, $db = 0) {
        return self::Pool_hGet($key, $mainId, $db);
    }
    
    public function hGetAll($key, $db = 0)
    {
        return self::Pool_hGetAll($key,$db);
    }
    
    public function hDel($key, $mainId, $db = 0)
    {
        return self::Pool_hDel($key, $mainId, $db);
    }
    public function hSet($key, $mainId, $value, $db = 0)
    {
        return  self::Pool_hSet($key, $mainId, $value,$db);
    }
    
    
    //TODO 初始化选择DB库(默认都使用0号库)
    protected static function commDb(&$redis,$db = 0){
        $redis->select(0);
    }
    
    /**************************************ADD NEW ******************FUNCTION *****************************/
    
    public static function Pool_get($key, $db = 0)
    {
        return RedisPool::invoke(function (RedisServer $redis) use ($key, $db) {
            self::commDb($redis,$db);   //初始化DB选择器
            return $redis->get($key);
        });
    }
    public static function Pool_keys($key, $db = 0)
    {
        return RedisPool::invoke(function (RedisServer $redis) use ($key, $db) {
            self::commDb($redis,$db);   //初始化DB选择器
            return $redis->keys($key);
        });
    }
    public static function Pool_set($key, $value, $timeout, $db = 0)
    {
        return RedisPool::invoke(function (RedisServer $redis) use ($key, $value, $timeout, $db) {
            self::commDb($redis,$db);   //初始化DB选择器
            return $redis->set($key, $value, $timeout);
        });
    }
    public static function Pool_del($key, $db = 0)
    {
        return RedisPool::invoke(function (RedisServer $redis) use ($key, $db) {
            self::commDb($redis,$db);   //初始化DB选择器
            return $redis->del($key);
        });
    }
    public static function Pool_hDel($key, $mainId, $db = 0) {
        return RedisPool::invoke(function (RedisServer $redis) use ($key, $mainId, $db) {
            self::commDb($redis,$db);   //初始化DB选择器
            return $redis->hDel($key, $mainId);
        });
    }
    public static function Pool_hSet($key, $mainId, $value, $db = 0)
    {
        return RedisPool::invoke(function (RedisServer $redis) use ($key, $value, $mainId, $db) {
            self::commDb($redis,$db);   //初始化DB选择器
            return $redis->hSet($key, $mainId, $value);
        });
    }
    public static function Pool_hGet($key, $mainId, $db = 0)
    {
        try {
            return RedisPool::invoke(function (RedisServer $redis) use ($key, $mainId, $db) {
                self::commDb($redis,$db);   //初始化DB选择器
                return $redis->hGet($key, $mainId);
            });
        } catch (\Throwable $throwable) {
            return FALSE;
        }
    }
    public static function Pool_hExists($key, $mainId, $db = 0)
    {
        return RedisPool::invoke(function (RedisServer $redis) use ($key, $mainId, $db) {
            self::commDb($redis,$db);   //初始化DB选择器
            return $redis->hExists($key, $mainId);
        });
    }
    public static function Pool_hAllKeys($key, $db = 0)
    {
        try {
            return RedisPool::invoke(function (RedisServer $redis) use ($key, $db) {
                self::commDb($redis,$db);       //初始化DB选择器
                return $redis->hKeys($key);
            });
        } catch (\Throwable $throwable) {
            return FALSE;
        }
    }
    public static function Pool_hGetAll($key, $db = 0)
    {
        return RedisPool::invoke(function (RedisServer $redis) use ($key, $db) {
            self::commDb($redis,$db);   //初始化DB选择器
            $allArray = [];
            $allvals = $redis->hKeys($key);
            if(!empty($allvals) && !empty($allvals)){
                foreach ($allvals as $linekk) {
                    $allArray[$linekk] = $redis->hGet($key, $linekk);   //取数组值
                }
            }
            return $allArray;
        });
    }
    
    //清空所有数据
    public static function Pool_FlushAll($delKeys = FALSE){
        return RedisPool::invoke(function (RedisServer $redis) use($delKeys){
            $total = 0;
            if (!$delKeys) { return $redis->flushAll();} //清理所有数据
            if (!empty($delKeys) && sizeof($delKeys)>0) {
                foreach ($delKeys as $onekey) {
                    if (!empty($onekey) && substr($onekey, -2) == "**") {  //取列表值
                        $allKeys = $redis->keys($onekey);
                        if(!empty($allKeys)){
                            //清掉所有KEY
                            foreach ($allKeys as $fhk){$redis->del($fhk);}  
                            $total ++;
                        }
                    }else{
                        $redis->del($onekey);    //清掉单个KEY
                        $total ++;
                    }
                }
            }
            return $total;
        });
    }
    
    /**
     * TODO  共享内存锁功能
     * TODO 解决高并发条件下的一些数据获取数据先后问题
     */
    public static function PublicLockedKey($key, $value , $callFun ,$db = 0){
        
        //TODO 处理内存方面的数据锁
        return RedisPool::invoke(function (RedisServer $redis) use ($key, $value, $callFun , $db) {
            self::commDb($redis,$db);   //初始化DB选择器
            $lock_timelong = 5;
            $ifLock = $redis->set($key, $value,$lock_timelong ,array('nx', 'ex' => $lock_timelong));
            if ($ifLock) {
                @call_user_func($callFun);
                if ($redis->get($key) == $value) {
                    $redis->del($key); //删除锁的KEY
                }
                return TRUE;
            }
            return FALSE;
        });
    }
    
    
    /***********第二种方案 [匿名连接池]***************************ADD NEW ******************FUN END *****************************/
    
    
    
    /**
     * TODO 获取连接池REDIS对象
     * TO 注意要及时回收getRedis和recycleRedis必须成对使用
     */
    public static function getRedis()
    {
        return Redis::getInstance()->pool(self::poolName)->getObj();
    }

    /**
     * TODO 回收getRedis
     *
     * @param Redis $redis
     */
    public static function recycleRedis(Redis $redis)
    {
        Redis::getInstance()->pool(self::poolName)->recycleObj($redis);
    }

    // 获取KEY值
    public static function getKeys($key, $db = 0)
    {
        return Redis::invoker(self::poolName, function (Connection $redis) use ($key, $db) {
            // $redis->select($db);
            return $redis->keys($key);
        });
    }

    // 获取KEY值
    public static function getKeyValue($key, $db = 0)
    {
        return Redis::invoker(self::poolName, function (Connection $redis) use ($key, $db) {
            // $redis->select($db);
            return $redis->get($key);
        });
    }

    // 设置KEY值
    public static function setKeyValue($key, $value, $timeout = null, $db = 0)
    {
        Redis::invoker(self::poolName, function (Connection $redis) use ($key, $value, $timeout, $db) {
            $redis->set($key, $value, $timeout);
        });
    }

    // 获取所有KEY
    public static function hGetPoolALL($key, $db = 0)
    {
        return Redis::invoker(self::poolName, function (Connection $redis) use ($key, $db) {
            // $redis->select($db);
            return $redis->hGetAll($key);
        });
    }

    // 获取Map值
    public static function hGetKeyValue($key, $mainId, $db = 0)
    {
        return Redis::invoker(self::poolName, function (Connection $redis) use ($key, $mainId, $db) {
            // $redis->select($db);
            return $redis->hGet($key, $mainId);
        });
    }

    // 设置Map值
    public static function hSetKeyValue($key, $mainId, $value = null, $db = 0)
    {
        Redis::invoker(self::poolName, function (Connection $redis) use ($key, $value, $mainId, $db) {
            // $redis->select($db);
            $redis->hSet($key, $mainId, $value);
        });
        return 1;
    }
}